<?php

namespace Tests;

use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

abstract class TestCase extends BaseTestCase
{
  use CreatesApplication;

  protected static $model;
  protected static $table;
  protected static $searchExpr = '';
  protected static $searchRecord;
  protected static $searchToUpd;
  protected static $searchToDel = [];
  protected static $toIns;
  protected static $toUpd = [];

  public function testShouldReturnAll()
  {
    $credentials = $headers = [];
    $token = '';
    $response = null;

    $credentials = [
      'email' => 'francisco.ramon@starlab.com',
      'password' => 'iamthevibe',
    ];
    $token = $this->getToken($credentials);
    $headers = [
      'Authorization' => 'Bearer ' . $token,
    ];

    $response = $this->withHeaders($headers)->json('GET', '/api/v1/' . self::$table);
    $response->assertStatus(200);

    $this->assertArrayHasKey('data', $response->json());
  }

  public function testShouldSearchAndReturnOne()
  {
    $credentials = $headers = [];
    $token = '';
    $response = null;

    $credentials = [
      'email' => 'francisco.ramon@starlab.com',
      'password' => 'iamthevibe',
    ];
    $token = $this->getToken($credentials);
    $headers = [
      'Authorization' => 'Bearer ' . $token,
    ];

    $response = $this->withHeaders($headers)->json('GET', '/api/v1/' . self::$table . '?' . self::$searchExpr);

    $response->assertStatus(200);
    $this->assertArrayHasKey('data', $response->json());
    $this->assertCount(1, $response->json('data'));
  }

  public function testShouldReturnOne()
  {
    $credentials = $headers = [];
    $token = '';
    $response = null;
    $id = 0;

    $credentials = [
      'email' => 'francisco.ramon@starlab.com',
      'password' => 'iamthevibe',
    ];
    $token = $this->getToken($credentials);
    $headers = [
      'Authorization' => 'Bearer ' . $token,
    ];

    $id = $this->getId(self::$searchRecord);
    $response = $this->withHeaders($headers)->json('GET', '/api/v1/' . self::$table . "/{$id}");

    $response->assertStatus(200);
  }

  public function testShouldCreate()
  {
    $credentials = $headers = [];
    $token = '';
    $response = null;

    $credentials = [
      'email' => 'francisco.ramon@starlab.com',
      'password' => 'iamthevibe',
    ];
    $token = $this->getToken($credentials);
    $headers = [
      'Authorization' => 'Bearer ' . $token,
    ];

    $response = $this->withHeaders($headers)->json('POST', '/api/v1/' . self::$table, self::$toIns);

    $response->assertStatus(201);
    $this->assertStringContainsString(trans('coreapi.resource_created'), $response->json('message'));
  }

  public function testShouldUpdateOne()
  {
    $credentials = $headers = [];
    $token = '';
    $response = null;
    $id = 0;

    $credentials = [
      'email' => 'francisco.ramon@starlab.com',
      'password' => 'iamthevibe',
    ];
    $token = $this->getToken($credentials);
    $headers = [
      'Authorization' => 'Bearer ' . $token,
    ];

    $id = $this->getId(self::$searchToUpd);
    $response = $this->withHeaders($headers)->json('PUT', '/api/v1/' . self::$table . "/{$id}", self::$toUpd);

    $response->assertStatus(200);
    $this->assertStringContainsString(trans('coreapi.resource_updated'), $response->json('message'));
  }

  public function testShouldDeleteOne()
  {
    $credentials = $headers = [];
    $token = '';
    $response = null;
    $id = 0;

    $credentials = [
      'email' => 'francisco.ramon@starlab.com',
      'password' => 'iamthevibe',
    ];
    $token = $this->getToken($credentials);
    $headers = [
      'Authorization' => 'Bearer ' . $token,
    ];

    $id = $this->getId(self::$searchToDel);
    $response = $this->withHeaders($headers)->json('DELETE', '/api/v1/' . self::$table . "/{$id}");

    $response->assertStatus(200);
    $this->assertStringContainsString(trans('coreapi.resource_deleted'), $response->json('message'));
  }

  private function getToken(array $credentials): string
  {
    $response = null;

    $response = $this->json('POST', '/api/v1/login', $credentials);

    return $response->json(['coreapi_token']);
  }

  private function getId(array $conds)
  {
    $id = 0;

    switch (count($conds)) {
      case 3:
        $id = self::$model::where(
          $conds[0],
          $conds[1],
          $conds[2]
        )->first()->id;

        break;

      case 6:
        $id = self::$model::where(
          $conds[0],
          $conds[1],
          $conds[2]
        )->where(
          $conds[3],
          $conds[4],
          $conds[5]
        )->first()->id;

        break;
    }

    return $id;
  }
}
